home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktime vr / vrspeech / common files / qtvrutilities.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  31.6 KB  |  1,106 lines

  1. //////////
  2. //
  3. //    File:        QTVRUtilities.c
  4. //
  5. //    Contains:    Some utilities for working with QuickTime VR movies.
  6. //                All utilities start with the prefix "QTVRUtils_".
  7. //
  8. //    Written by:    Tim Monroe
  9. //
  10. //    Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <24>         04/05/99    rtm        added QTVRUtils_IsBackBufferHorizontal
  15. //       <23>         03/11/99    rtm        moved _GetControllerType and _SetControllerType to QTUtilities
  16. //       <22>         02/03/99    rtm        moved non-QTVR-specific utilities to QTUtilities
  17. //       <21>         02/12/98    rtm        added QTVRUtils_HideHotSpotNames and her sisters, *Show* and *Toggle*
  18. //       <20>         01/27/98    rtm        revised QTVRUtils_IsQTVRMgrInstalled and QTVRUtils_GetQTVRVersion
  19. //       <19>         01/26/98    rtm        revised QTVRUtils_GetHotSpotName to look also in hot spot atom for name atom
  20. //       <18>         01/14/98    rtm        added QTVRUtils_SetControllerType and QTVRUtils_AddStr255ToAtomContainer
  21. //       <17>         10/20/97    rtm        added QTVRUtils_IsMultiNode; added Endian*_BtoN macros to file format routines
  22. //       <16>         10/17/97    rtm        fixed QTVRUtils_IsControllerButtonVisible behavior for speaker button
  23. //       <15>         10/07/97    rtm        added cannotFindAtomErr result code to QTVRUtils_Get*AtomData functions
  24. //       <14>         09/15/97    rtm        added QTVRUtils_ToggleControllerBar
  25. //       <13>         08/21/97    rtm        added QTVRUtils_IsControllerButtonVisible
  26. //       <12>         08/19/97    rtm        added #ifdefs to support Windows compilation
  27. //       <11>         08/05/97    rtm        added QTVRUtils_GetNodeComment; still needs testing
  28. //       <10>         07/27/97    rtm        fixed QTVRUtils_GetHotSpotCount; added QTVRUtils_GetHotSpotIDByIndex
  29. //       <9>         07/25/97    rtm        revised QTVRUtils_Get*AtomData functions to use QTCopyAtomDataToPtr;
  30. //                                    rewrote QTVRUtils_GetStringFromAtom
  31. //       <8>         07/24/97    rtm        removed sound volume utilities; added QTVRUtils_IsZoomAvailable;
  32. //                                    revised QTVRUtils_IsQTVRMovie to use GetUserDataItem, not GetUserData
  33. //       <7>         07/23/97    rtm        revised file format utilities; added QTVRUtils_Get*AtomData functions
  34. //       <6>         07/22/97    rtm        fixed QTVRUtils_GetHotSpotCount to make sure handle is actually resized
  35. //       <5>         07/21/97    rtm        added QTVRUtils_GetNodeCount
  36. //       <4>         06/04/97    rtm        fixed QTVRUtils_ShowControllerButton and QTVRUtils_HideControllerButton,
  37. //                                    and added some explanation of them; added QTVRUtils_ResetControllerButton
  38. //       <3>         02/03/97    rtm        revised QTVRUtils_ShowControllerButton and QTVRUtils_HideControllerButton 
  39. //                                    to use explicit flag
  40. //       <2>         12/03/96    rtm        added controller bar utilities
  41. //       <1>         11/27/96    rtm        first file
  42. //       
  43. //////////
  44.  
  45. //////////
  46. //
  47. // header files
  48. //
  49. //////////
  50.  
  51. #ifndef __QTVRUtilities__
  52. #include "QTVRUtilities.h"
  53. #endif
  54.  
  55. #ifndef __QTUtilities__
  56. #include "QTUtilities.h"
  57. #endif
  58.  
  59. #include <math.h>
  60. #include <stdlib.h>
  61. #include <string.h>
  62.  
  63.  
  64.  
  65. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  66. //
  67. // General utilities.
  68. //
  69. // Use these functions to get information about the availability/features of QuickTime VR or other services.
  70. //
  71. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  72.  
  73. //////////
  74. //
  75. // QTVRUtils_IsQTVRMgrInstalled
  76. // Is the QuickTime VR Manager installed?
  77. //
  78. //////////
  79.  
  80. Boolean QTVRUtils_IsQTVRMgrInstalled (void) 
  81. {
  82.     Boolean     myQTVRAvail = false;
  83.     long        myAttrs;
  84.     OSErr         myErr = noErr;
  85.  
  86.     myErr = Gestalt(gestaltQTVRMgrAttr, &myAttrs);
  87.     if (myErr == noErr)
  88.         if (myAttrs & (1L << gestaltQTVRMgrPresent))
  89.             myQTVRAvail = true;
  90.  
  91.     return(myQTVRAvail);
  92. }
  93.  
  94.  
  95. //////////
  96. //
  97. // QTVRUtils_GetQTVRVersion
  98. // Get the version of the QuickTime VR Manager installed.
  99. //
  100. // The low-order word of the returned long integer contains the version number,
  101. // so you can test a version like this:
  102. //
  103. //        if (QTVRUtils_GetQTVRVersion() < 0x0210)        // we require QTVR 2.1 or greater
  104. //            return;
  105. //
  106. //////////
  107.  
  108. long QTVRUtils_GetQTVRVersion (void)
  109. {
  110.     long         myVersion = 0L;
  111.     OSErr         myErr = noErr;
  112.  
  113.     myErr = Gestalt(gestaltQTVRMgrVers, &myVersion);
  114.     if (myErr == noErr)
  115.         return(myVersion);
  116.     else
  117.         return(0L);
  118. }
  119.  
  120.  
  121. //////////
  122. //
  123. // QTVRUtils_IsQTVRMovie
  124. // Is the specified movie a QTVR movie?
  125. //
  126. // WARNING: This function is intended for use ONLY when you want to determine if you've got a QTVR movie
  127. // but you don't want to use the QuickTime VR API (perhaps QTVR isn't installed...). The preferred way to
  128. // determine if a movie is a QTVR movie is to call QTVRGetQTVRTrack and then QTVRGetQTVRInstance; if you
  129. // get back a non-NULL instance, you've got a QTVR movie.
  130. //
  131. //////////
  132.  
  133. Boolean QTVRUtils_IsQTVRMovie (Movie theMovie) 
  134. {
  135.     Boolean            myIsQTVRMovie = false;
  136.     OSType            myType;
  137.     
  138.     // QTVR movies have a special piece of user data identifying the movie controller type
  139.     myType = QTUtils_GetControllerType(theMovie);
  140.     
  141.     if ((myType == kQTVRQTVRType) || (myType == kQTVROldPanoType) || (myType == kQTVROldObjectType))
  142.         myIsQTVRMovie = true; 
  143.         
  144.     return(myIsQTVRMovie);
  145. }
  146.  
  147.  
  148. //////////
  149. //
  150. // QTVRUtils_Is20QTVRMovie
  151. // Is the specified QTVR movie version 2.0 or greater?
  152. //
  153. //////////
  154.  
  155. Boolean QTVRUtils_Is20QTVRMovie (Movie theMovie) 
  156. {
  157.     Boolean            myIs20QTVRMovie = false;
  158.     OSType            myType;
  159.     
  160.     // QTVR movies have a special piece of user data identifying the movie controller type
  161.     myType = QTUtils_GetControllerType(theMovie);
  162.     
  163.     if (myType == kQTVRQTVRType)
  164.         myIs20QTVRMovie = true; 
  165.         
  166.     return(myIs20QTVRMovie);
  167. }
  168.  
  169.  
  170. //////////
  171. //
  172. // QTVRUtils_IsTranslateAvailable
  173. // Is translation currently enabled for the specified object node?
  174. //
  175. //////////
  176.  
  177. Boolean QTVRUtils_IsTranslateAvailable (QTVRInstance theInstance) 
  178. {
  179.     Boolean        myState;
  180.     
  181.     QTVRGetControlSetting(theInstance, kQTVRTranslation, &myState);
  182.     return(myState);
  183. }
  184.  
  185.  
  186. //////////
  187. //
  188. // QTVRUtils_IsZoomAvailable
  189. // Is zooming currently enabled for the specified object node?
  190. //
  191. //////////
  192.  
  193. Boolean QTVRUtils_IsZoomAvailable (QTVRInstance theInstance) 
  194. {
  195.     Boolean        myState;
  196.     
  197.     QTVRGetControlSetting(theInstance, kQTVRCanZoom, &myState);
  198.     return(myState);
  199. }
  200.  
  201.  
  202. //////////
  203. //
  204. // QTVRUtils_IsPanoNode
  205. // Is the specified node a panoramic node?
  206. //
  207. //////////
  208.  
  209. Boolean QTVRUtils_IsPanoNode (QTVRInstance theInstance) 
  210. {
  211.     return(QTVRGetNodeType(theInstance, kQTVRCurrentNode) == kQTVRPanoramaType);
  212. }
  213.  
  214.  
  215. //////////
  216. //
  217. // QTVRUtils_IsObjectNode
  218. // Is the specified node an object node?
  219. //
  220. //////////
  221.  
  222. Boolean QTVRUtils_IsObjectNode (QTVRInstance theInstance) 
  223. {
  224.     return(QTVRGetNodeType(theInstance, kQTVRCurrentNode) == kQTVRObjectType);
  225. }
  226.  
  227.  
  228. //////////
  229. //
  230. // QTVRUtils_IsHotSpotInNode
  231. // Does the specified node contain at least one hot spot (whether visible, enabled, or whatever)?
  232. //
  233. // NOTE: This is not an easy function to implement using just the QTVR 2.1 API. We do have our own
  234. // utility QTVRUtils_GetHotSpotCount, but that function returns the number of hot spot information atoms
  235. // in the node, which is not (necessarily) the number of hot spot regions in the hot spot image track.
  236. // For panoramas, we could check to see if the panorama sample atom structure contains a reference
  237. // to a hot spot image track; if it does, we'd blindly assume that that track isn't empty. For objects,
  238. // we'll have to rely on QTVRUtils_GetHotSpotCount. So it goes....
  239. //
  240. // In an ideal world, there would be a hot spot information atom for each and every hot spot region in
  241. // the hot spot image track, in which case we could be happier using QTVRUtils_GetHotSpotCount.
  242. //
  243. //////////
  244.  
  245. Boolean QTVRUtils_IsHotSpotInNode (QTVRInstance theInstance) 
  246. {
  247.     return(QTVRUtils_GetHotSpotCount(theInstance, QTVRGetCurrentNodeID(theInstance), NULL) > 0);
  248. }
  249.  
  250.  
  251. //////////
  252. //
  253. // QTVRUtils_IsMultiNode
  254. // Does the specified QuickTime VR instance contain more than one node?
  255. //
  256. //////////
  257.  
  258. Boolean QTVRUtils_IsMultiNode (QTVRInstance theInstance) 
  259. {
  260.     return(QTVRUtils_GetNodeCount(theInstance) > (UInt32)1);
  261. }
  262.  
  263.  
  264. //////////
  265. //
  266. // QTVRUtils_IsBackBufferHorizontal
  267. // Is the back buffer oriented horizontally?
  268. //
  269. //////////
  270.  
  271. Boolean QTVRUtils_IsBackBufferHorizontal (QTVRInstance theInstance)
  272. {
  273.     UInt32        myGeometry;
  274.     UInt16        myResolution;
  275.     UInt32        myCachePixelFormat;
  276.     SInt16        myCacheSize;
  277.  
  278.     QTVRGetBackBufferSettings(theInstance, &myGeometry, &myResolution, &myCachePixelFormat, &myCacheSize);
  279.     return(myGeometry == kQTVRHorizontalCylinder);
  280. }
  281.  
  282.  
  283. //////////
  284. //
  285. // QTVRUtils_HideHotSpotNames
  286. // Disable the displaying of hot spot names in the controller bar.
  287. //
  288. //////////
  289.  
  290. void QTVRUtils_HideHotSpotNames (MovieController theMC) 
  291. {
  292.     QTUtils_HideControllerButton(theMC, kQTVRHotSpotNames);
  293. }
  294.  
  295.  
  296. //////////
  297. //
  298. // QTVRUtils_ShowHotSpotNames
  299. // Enable the displaying of hot spot names in the controller bar.
  300. //
  301. //////////
  302.  
  303. void QTVRUtils_ShowHotSpotNames (MovieController theMC) 
  304. {
  305.     QTUtils_ShowControllerButton(theMC, kQTVRHotSpotNames);
  306. }
  307.  
  308.  
  309. //////////
  310. //
  311. // QTVRUtils_ToggleHotSpotNames
  312. // Toggle the displaying of hot spot names in the controller bar.
  313. //
  314. //////////
  315.  
  316. void QTVRUtils_ToggleHotSpotNames (MovieController theMC) 
  317. {
  318.     QTUtils_ToggleControllerButton(theMC, kQTVRHotSpotNames);
  319. }
  320.  
  321.  
  322. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  323. //
  324. // File format utilities.
  325. //
  326. // Use these functions to read information from QuickTime VR files that's not accessible using the API.
  327. // Throughout, we assume that we're dealing with format 2.0 files. We begin with a series of functions that
  328. // return a pointer to the data in an atom (QTVRUtils_Get*AtomData); you probably won't use these functions
  329. // directly.
  330. //
  331. // Keep in mind that data stored in QuickTime atoms is big-endian. We'll need to convert any multi-byte data
  332. // that we read from an atom to native format before we use it.
  333. //
  334. // Note that these file format utilities are all Getters. As yet, no Setters. Perhaps later?
  335. //
  336. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  337.  
  338. //////////
  339. //
  340. // QTVRUtils_GetVRWorldHeaderAtomData
  341. // Get a pointer to the VR world header atom data in a QTVR movie.
  342. //
  343. //////////
  344.  
  345. OSErr QTVRUtils_GetVRWorldHeaderAtomData (QTVRInstance theInstance, QTVRWorldHeaderAtomPtr theVRWorldHdrAtomPtr)
  346. {
  347.     QTAtomContainer            myVRWorld;
  348.     QTAtom                    myAtom;
  349.     OSErr                    myErr = noErr;
  350.         
  351.     // get the VR world
  352.     myErr = QTVRGetVRWorld(theInstance, &myVRWorld);
  353.     if (myErr != noErr)
  354.         return(myErr);
  355.     
  356.     // get the single VR world header atom in the VR world
  357.     myAtom = QTFindChildByIndex(myVRWorld, kParentAtomIsContainer, kQTVRWorldHeaderAtomType, 1, NULL);
  358.     if (myAtom != 0)
  359.         myErr = QTCopyAtomDataToPtr(myVRWorld, myAtom, false, sizeof(QTVRWorldHeaderAtom), theVRWorldHdrAtomPtr, NULL);
  360.     else 
  361.         myErr = cannotFindAtomErr;
  362.     
  363.     QTDisposeAtomContainer(myVRWorld);
  364.     return(myErr);
  365. }
  366.  
  367.  
  368. //////////
  369. //
  370. // QTVRUtils_GetNodeHeaderAtomData
  371. // Get a pointer to the node header atom data for the node having the specified node ID.
  372. //
  373. //////////
  374.  
  375. OSErr QTVRUtils_GetNodeHeaderAtomData (QTVRInstance theInstance, UInt32 theNodeID, QTVRNodeHeaderAtomPtr theNodeHdrPtr)
  376. {
  377.     QTAtomContainer            myNodeInfo;
  378.     QTAtom                    myAtom;
  379.     OSErr                    myErr = noErr;
  380.         
  381.     // get the node information atom container for the specified node
  382.     myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  383.     if (myErr != noErr)
  384.         return(myErr);
  385.     
  386.     // get the single node header atom in the node information atom container
  387.     myAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRNodeHeaderAtomType, 1, NULL);
  388.     if (myAtom != 0)
  389.         myErr = QTCopyAtomDataToPtr(myNodeInfo, myAtom, false, sizeof(QTVRNodeHeaderAtom), theNodeHdrPtr, NULL);
  390.     else 
  391.         myErr = cannotFindAtomErr;
  392.  
  393.     QTDisposeAtomContainer(myNodeInfo);
  394.     return(myErr);
  395. }
  396.  
  397.  
  398. //////////
  399. //
  400. // QTVRUtils_GetHotSpotAtomData
  401. // Get a pointer to the hot spot atom data for hot spot having the specified hot spot ID in the specified node.
  402. //
  403. //////////
  404.  
  405. OSErr QTVRUtils_GetHotSpotAtomData (QTVRInstance theInstance, UInt32 theNodeID, UInt32 theHotSpotID, QTVRHotSpotInfoAtomPtr theHotSpotInfoPtr)
  406. {
  407.     QTAtomContainer            myNodeInfo;
  408.     QTAtom                    myHSParentAtom;
  409.     OSErr                    myErr = noErr;
  410.         
  411.     // (1) the node information atom container contains a *hot spot parent atom*;
  412.     // (2) the hot spot parent atom contains one or more *hot spot atoms*;
  413.     // (3) the hot spot atom contains two children, a *general hot spot information atom*
  414.     //     and a *specific hot spot information atom*.
  415.     // We want to return a pointer to the general hot spot information atom data.
  416.  
  417.     // get the node information atom container for the specified node
  418.     myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  419.     if (myErr != noErr)
  420.         return(myErr);
  421.     
  422.     // get the single hot spot parent atom in the node information atom container
  423.     myHSParentAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRHotSpotParentAtomType, 1, NULL);
  424.     if (myHSParentAtom != 0) {
  425.         QTAtom                myHSAtom;
  426.         
  427.         // get the hot spot atom whose atom ID is the specified hot spot ID
  428.         myHSAtom = QTFindChildByID(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType, theHotSpotID, NULL);
  429.         if (myHSAtom != 0) {
  430.             QTAtom            myAtom;
  431.             
  432.             // get the single hot spot information atom in the hot spot atom
  433.             myAtom = QTFindChildByIndex(myNodeInfo, myHSAtom, kQTVRHotSpotInfoAtomType, 1, NULL);
  434.             if (myAtom != 0) {
  435.                 myErr = QTCopyAtomDataToPtr(myNodeInfo, myAtom, false, sizeof(QTVRHotSpotInfoAtom), theHotSpotInfoPtr, NULL);
  436.             }
  437.         } else {
  438.             myErr = cannotFindAtomErr;
  439.         }
  440.     } else {
  441.         myErr = cannotFindAtomErr;
  442.     }
  443.  
  444.     QTDisposeAtomContainer(myNodeInfo);
  445.     return(myErr);
  446. }
  447.  
  448.  
  449. //////////
  450. //
  451. // QTVRUtils_GetStringFromAtom
  452. // Get the string data from the string atom having the specified ID in the specified atom container.
  453. //
  454. // We use a different strategy here, since we don't know the size of the string data in advance.
  455. //
  456. //////////
  457.  
  458. char *QTVRUtils_GetStringFromAtom (QTAtomContainer theContainer, QTAtom theParent, QTAtomID theID)
  459. {
  460.     QTVRStringAtomPtr    myStringAtomPtr = NULL;
  461.     QTAtom                myNameAtom;
  462.     char                *myString = NULL;
  463.      OSErr                myErr = noErr;
  464.  
  465.     if (theContainer == NULL)
  466.         return(myString);
  467.         
  468.     QTLockContainer(theContainer);
  469.     
  470.     myNameAtom = QTFindChildByID(theContainer, theParent, kQTVRStringAtomType, theID, NULL);
  471.     if (myNameAtom != 0) {
  472.         myErr = QTGetAtomDataPtr(theContainer, myNameAtom, NULL, (Ptr *)&myStringAtomPtr);
  473.         if ((myErr == noErr) && (myStringAtomPtr != NULL)) {
  474.             UInt16        myLength;
  475.                 
  476.             myLength = EndianU16_BtoN(myStringAtomPtr->stringLength);
  477.             if (myLength > 0) {
  478.                 myString = malloc(myLength + 1);
  479.                 if (myString != NULL) {
  480.                     memcpy(myString, myStringAtomPtr->theString, myLength);
  481.                     myString[myLength] = '\0';
  482.                 }
  483.             }            
  484.         }
  485.     }
  486.     
  487.     QTUnlockContainer(theContainer);
  488.     return(myString);
  489. }
  490.  
  491.  
  492. //////////
  493. //
  494. // QTVRUtils_AddStr255ToAtomContainer
  495. // Add a Pascal string to the specified atom container; return (through theID) the ID of the new string atom.
  496. //
  497. //////////
  498.  
  499. OSErr QTVRUtils_AddStr255ToAtomContainer (QTAtomContainer theContainer, QTAtom theParent, Str255 theString, QTAtomID *theID)
  500. {
  501.     OSErr                    myErr = noErr;
  502.  
  503.     *theID = 0;                // initialize the returned atom ID
  504.     
  505.     if ((theContainer == NULL) || (theParent == 0))
  506.         return(paramErr);
  507.         
  508.     if (theString[0] != 0) {
  509.         QTAtom                myStringAtom;
  510.         UInt16                mySize;
  511.         QTVRStringAtomPtr    myStringAtomPtr = NULL;
  512.         
  513.         mySize = sizeof(QTVRStringAtom) - 4 + theString[0] + 1;
  514.         myStringAtomPtr = (QTVRStringAtomPtr)NewPtrClear(mySize);
  515.         
  516.         if (myStringAtomPtr != NULL) {
  517.             myStringAtomPtr->stringUsage = EndianU16_NtoB(1);
  518.             myStringAtomPtr->stringLength = EndianU16_NtoB(theString[0]);
  519.             BlockMove(theString + 1, myStringAtomPtr->theString, theString[0]);
  520.             myStringAtomPtr->theString[theString[0]] = '\0';
  521.             myErr = QTInsertChild(theContainer, theParent, kQTVRStringAtomType, 0, 0, mySize, (Ptr)myStringAtomPtr, &myStringAtom);
  522.             DisposePtr((Ptr)myStringAtomPtr);
  523.             
  524.             if (myErr == noErr)
  525.                 QTGetAtomTypeAndID(theContainer, myStringAtom, NULL, theID);
  526.         }
  527.     }
  528.     
  529.     return(myErr);
  530. }
  531.  
  532.  
  533. //////////
  534. //
  535. // QTVRUtils_GetDefaultNodeID
  536. // Get the ID of the default node in a QTVR movie.
  537. //
  538. //////////
  539.  
  540. UInt32 QTVRUtils_GetDefaultNodeID (QTVRInstance theInstance)
  541. {
  542.     QTVRWorldHeaderAtom         myVRWorldHeader;
  543.     UInt32                    myNodeID = kQTVRCurrentNode;
  544.     OSErr                    myErr = noErr;
  545.         
  546.     myErr = QTVRUtils_GetVRWorldHeaderAtomData(theInstance, &myVRWorldHeader);
  547.     if (myErr == noErr)
  548.         myNodeID = EndianU32_BtoN(myVRWorldHeader.defaultNodeID);
  549.  
  550.     return(myNodeID);
  551. }
  552.  
  553.  
  554. //////////
  555. //
  556. // QTVRUtils_GetSceneFlags
  557. // Get the set of flags associated with the VR scene.
  558. // (Currently these flags are undefined, however.)
  559. //
  560. //////////
  561.  
  562. UInt32 QTVRUtils_GetSceneFlags (QTVRInstance theInstance)
  563. {
  564.     QTVRWorldHeaderAtom         myVRWorldHeader;
  565.     UInt32                    myFlags = 0L;
  566.     OSErr                    myErr;
  567.         
  568.     myErr = QTVRUtils_GetVRWorldHeaderAtomData(theInstance, &myVRWorldHeader);
  569.     if (myErr == noErr)
  570.         myFlags = EndianU32_BtoN(myVRWorldHeader.vrWorldFlags);
  571.  
  572.     return(myFlags);
  573. }
  574.  
  575.  
  576. //////////
  577. //
  578. // QTVRUtils_GetSceneName
  579. // Get the name of the VR scene.
  580. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  581. //
  582. //////////
  583.  
  584. char *QTVRUtils_GetSceneName (QTVRInstance theInstance)
  585. {
  586.     QTVRWorldHeaderAtom             myVRWorldHeader;
  587.     char                        *mySceneName = NULL;
  588.     OSErr                        myErr = noErr;
  589.         
  590.     myErr = QTVRUtils_GetVRWorldHeaderAtomData(theInstance, &myVRWorldHeader);
  591.     if (myErr == noErr) {
  592.         QTAtomID                myNameAtomID;
  593.         
  594.         // get the atom ID of the name string atom
  595.         myNameAtomID = EndianU32_BtoN(myVRWorldHeader.nameAtomID);
  596.         
  597.         if (myNameAtomID != 0) {
  598.             QTAtomContainer        myVRWorld;
  599.             
  600.             // the string atom containing the name of the scene is a *sibling* of the VR world header atom
  601.             myErr = QTVRGetVRWorld(theInstance, &myVRWorld);
  602.             if (myErr == noErr)
  603.                 mySceneName = QTVRUtils_GetStringFromAtom(myVRWorld, kParentAtomIsContainer, myNameAtomID);
  604.             
  605.             QTDisposeAtomContainer(myVRWorld);
  606.         }
  607.     }
  608.  
  609.     return(mySceneName);
  610. }
  611.  
  612.  
  613. //////////
  614. //
  615. // QTVRUtils_GetNodeCount
  616. // Get the number of nodes in a QTVR movie.
  617. //
  618. //////////
  619.  
  620. UInt32 QTVRUtils_GetNodeCount (QTVRInstance theInstance)
  621. {
  622.     QTAtomContainer            myVRWorld;
  623.     QTAtom                    myNodeParentAtom;
  624.     UInt32                    myNumNodes = 0;
  625.     OSErr                    myErr = noErr;
  626.  
  627.     // get the VR world
  628.     myErr = QTVRGetVRWorld(theInstance, &myVRWorld);
  629.     if (myErr != noErr)
  630.         return(myNumNodes);
  631.  
  632.     // get the node parent atom, whose children contain info about all nodes in the scene
  633.     myNodeParentAtom = QTFindChildByIndex(myVRWorld, kParentAtomIsContainer, kQTVRNodeParentAtomType, 1, NULL);
  634.     if (myNodeParentAtom != 0) {
  635.         // now count the node ID children of the node parent atom, which is the number of nodes in the scene
  636.         myNumNodes = QTCountChildrenOfType(myVRWorld, myNodeParentAtom, kQTVRNodeIDAtomType);
  637.     }    
  638.  
  639.     QTDisposeAtomContainer(myVRWorld);
  640.     
  641.     return(myNumNodes);
  642. }
  643.  
  644.  
  645. //////////
  646. //
  647. // QTVRUtils_GetNodeType
  648. // Get the type of the node with the specified ID.
  649. //
  650. // NOTE: This function is redundant, given QTVRGetNodeType; it's included here for illustrative purposes only.
  651. //
  652. //////////
  653.  
  654. OSErr QTVRUtils_GetNodeType (QTVRInstance theInstance, UInt32 theNodeID, OSType *theNodeType)
  655. {
  656.     QTVRNodeHeaderAtom        myNodeHeader;
  657.     OSErr                    myErr = noErr;
  658.  
  659.     // make sure we always return some meaningful value
  660.     *theNodeType = kQTVRUnknownType;
  661.     
  662.     // get the node header atom data
  663.     myErr = QTVRUtils_GetNodeHeaderAtomData(theInstance, theNodeID, &myNodeHeader);
  664.     if (myErr == noErr)
  665.         *theNodeType = EndianU32_BtoN(myNodeHeader.nodeType);
  666.         
  667.     return(myErr);
  668. }
  669.  
  670.  
  671. //////////
  672. //
  673. // QTVRUtils_GetNodeName
  674. // Get the name of the node with the specified ID.
  675. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  676. //
  677. //////////
  678.  
  679. char *QTVRUtils_GetNodeName (QTVRInstance theInstance, UInt32 theNodeID)
  680. {
  681.     QTVRNodeHeaderAtom        myNodeHeader;
  682.     char                    *myNodeName = NULL;
  683.     OSErr                    myErr = noErr;
  684.     
  685.     myErr = QTVRUtils_GetNodeHeaderAtomData(theInstance, theNodeID, &myNodeHeader);
  686.     if (myErr == noErr) {
  687.         QTAtomID                myNameAtomID;
  688.         
  689.         // get the atom ID of the name string atom
  690.         myNameAtomID = EndianU32_BtoN(myNodeHeader.nameAtomID);
  691.         
  692.         if (myNameAtomID != 0) {
  693.             QTAtomContainer        myNodeInfo;
  694.             
  695.             // the string atom containing the name of the node is a *sibling* of the node information atom
  696.             myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  697.             if (myErr == noErr)
  698.                 myNodeName = QTVRUtils_GetStringFromAtom(myNodeInfo, kParentAtomIsContainer, myNameAtomID);
  699.  
  700.             QTDisposeAtomContainer(myNodeInfo);
  701.         }
  702.     }
  703.     
  704.     return(myNodeName);
  705. }
  706.  
  707.  
  708. //////////
  709. //
  710. // QTVRUtils_GetNodeComment
  711. // Get the comment for the node with the specified ID.
  712. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  713. //
  714. //////////
  715.  
  716. char *QTVRUtils_GetNodeComment (QTVRInstance theInstance, UInt32 theNodeID)
  717. {
  718.     QTVRNodeHeaderAtom        myNodeHeader;
  719.     char                    *myNodeCmt = NULL;
  720.     OSErr                    myErr = noErr;
  721.     
  722.     myErr = QTVRUtils_GetNodeHeaderAtomData(theInstance, theNodeID, &myNodeHeader);
  723.     if (myErr == noErr) {
  724.         QTAtomID                myCmtAtomID;
  725.         
  726.         // get the atom ID of the comment string atom
  727.         myCmtAtomID = EndianU32_BtoN(myNodeHeader.commentAtomID);
  728.         
  729.         if (myCmtAtomID != 0) {
  730.             QTAtomContainer        myNodeInfo;
  731.             
  732.             // the string atom containing the comment for the node is a *sibling* of the node information atom
  733.             myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  734.             if (myErr == noErr)
  735.                 myNodeCmt = QTVRUtils_GetStringFromAtom(myNodeInfo, kParentAtomIsContainer, myCmtAtomID);
  736.  
  737.             QTDisposeAtomContainer(myNodeInfo);
  738.         }
  739.     }
  740.     
  741.     return(myNodeCmt);
  742. }
  743.  
  744.  
  745. //////////
  746. //
  747. // QTVRUtils_GetHotSpotCount
  748. // Return the number of hot spots in the node with specified ID,
  749. // and fill the specified handle with a list of the hot spot IDs.
  750. //
  751. // If theHotSpotIDs == NULL on entry, do not pass back the list of IDs.
  752. //
  753. // WARNING: This routine determines the number of hot spots by counting
  754. // the hot spot atoms in a hot spot parent atom; this might not be
  755. // the same as counting the number of regions in the hot spot image track.
  756. // Sigh.
  757. //
  758. //////////
  759.  
  760. UInt32 QTVRUtils_GetHotSpotCount (QTVRInstance theInstance, UInt32 theNodeID, Handle theHotSpotIDs)
  761. {
  762.     QTAtomContainer            myNodeInfo;
  763.     QTAtom                    myHSParentAtom = 0;
  764.     UInt32                    myNumHotSpots = 0;
  765.     OSErr                    myErr = noErr;
  766.     
  767.     // get the node information atom container for the current node
  768.     myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  769.     
  770.     // get the hot spot parent atom
  771.     if (myErr == noErr)
  772.         myHSParentAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRHotSpotParentAtomType, 1, NULL);
  773.         
  774.     if (myHSParentAtom != 0) {
  775.         SignedByte            myHState;
  776.         Size                mySize;
  777.  
  778.         // get the number of hot spots in the current node
  779.         myNumHotSpots = QTCountChildrenOfType(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType);
  780.         
  781.         // now pass back a list of the hot spot IDs;
  782.         // if theHotSpotIDs is NULL on entry, we assume the caller doesn't want this information
  783.         if (theHotSpotIDs != NULL) {
  784.         
  785.             // unlock the handle, if it's locked (so that we can resize it)
  786.             myHState = HGetState(theHotSpotIDs);
  787.             if (myHState & 0x80)            // 0x80 == the block-is-locked bit in the SignedByte returned by HGetState
  788.                 HUnlock(theHotSpotIDs);
  789.  
  790.             // resize the handle to the appropriate size
  791.             mySize = sizeof(UInt32) * myNumHotSpots;
  792.             SetHandleSize(theHotSpotIDs, mySize);
  793.             
  794.             // restore the original handle state
  795.             HSetState(theHotSpotIDs, myHState);
  796.             
  797.             // make sure we actually did resize the handle
  798.             if (GetHandleSize(theHotSpotIDs) == mySize) {
  799.                 short            myIndex;
  800.                 QTAtom            myAtom;
  801.                 QTAtomID        myID;
  802.                 UInt32            *myIDPtr;
  803.                 
  804.                 myIDPtr = (UInt32 *)*theHotSpotIDs;
  805.  
  806.                 // loop thru all the hot spots to get their IDs
  807.                 for (myIndex = 1; myIndex <= (short)myNumHotSpots; myIndex++) {
  808.                     myAtom = QTFindChildByIndex(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType, myIndex, &myID);
  809.                     myIDPtr[myIndex - 1] = (UInt32)myID;
  810.                 }
  811.             }
  812.         }
  813.     }
  814.     
  815.     QTDisposeAtomContainer(myNodeInfo);
  816.     return(myNumHotSpots);
  817. }
  818.  
  819.  
  820. //////////
  821. //
  822. // QTVRUtils_GetHotSpotIDByIndex
  823. // Return the hot spot ID having the specified index in the list of hot spot IDs returned by QTVRUtils_GetHotSpotCount,
  824. // or kQTVRUtils_InvalidHotSpotID if no such hot spot exists.
  825. //
  826. //////////
  827.  
  828. UInt32 QTVRUtils_GetHotSpotIDByIndex (QTVRInstance theInstance, Handle theHotSpotIDs, UInt32 theIndex)
  829. {
  830.     Size            mySize;
  831.     UInt32            myID = kQTVRUtils_InvalidHotSpotID;
  832.     UInt32            *myIDPtr;
  833.                 
  834.     // make sure the instance and hot spot list are non-NULL
  835.     if ((theInstance == NULL) || (theHotSpotIDs == NULL))
  836.         return(myID);
  837.     
  838.     // make sure that the index is valid    
  839.     mySize = GetHandleSize(theHotSpotIDs);
  840.     if (theIndex >= (mySize / sizeof(UInt32)))
  841.         return(myID);
  842.  
  843.     myIDPtr = (UInt32 *)*theHotSpotIDs;
  844.     myID = myIDPtr[theIndex];
  845.     return(myID);
  846. }
  847.  
  848.  
  849. //////////
  850. //
  851. // QTVRUtils_GetHotSpotType
  852. // Return the type of the hot spot having the specified hot spot ID in the specified node.
  853. //
  854. // NOTE: This function is semi-redundant, given QTVRGetHotSpotType; it's included here for illustrative purposes only.
  855. // (Note, however, that QTVRGetHotSpotType returns types only for hot spots in the current node; here we do any node!)
  856. //
  857. //////////
  858.  
  859. OSErr QTVRUtils_GetHotSpotType (QTVRInstance theInstance, UInt32 theNodeID, UInt32 theHotSpotID, OSType *theHotSpotType)
  860. {
  861.     QTVRHotSpotInfoAtom        myHotSpotAtomData;
  862.     OSErr                    myErr = noErr;
  863.     
  864.     // make sure we always return some meaningful value
  865.     *theHotSpotType = kQTVRHotSpotUndefinedType;
  866.     
  867.     // get the hot spot information atom data
  868.     myErr = QTVRUtils_GetHotSpotAtomData(theInstance, theNodeID, theHotSpotID, &myHotSpotAtomData);
  869.     if (myErr == noErr)
  870.         *theHotSpotType = EndianU32_BtoN(myHotSpotAtomData.hotSpotType);        // return the hot spot type
  871.     
  872.     return(myErr);
  873. }
  874.  
  875.  
  876. //////////
  877. //
  878. // QTVRUtils_GetHotSpotName
  879. // Return the name of the hot spot having the specified hot spot ID in the specified node.
  880. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  881. //
  882. //////////
  883.  
  884. char *QTVRUtils_GetHotSpotName (QTVRInstance theInstance, UInt32 theNodeID, UInt32 theHotSpotID)
  885. {
  886.     QTVRHotSpotInfoAtom        myHotSpotAtomData;
  887.     char                    *myHotSpotName = NULL;
  888.     OSErr                    myErr = noErr;
  889.     
  890.     // get the hot spot information atom data
  891.     myErr = QTVRUtils_GetHotSpotAtomData(theInstance, theNodeID, theHotSpotID, &myHotSpotAtomData);
  892.     if (myErr == noErr) {
  893.         QTAtomID                myNameAtomID;
  894.         
  895.         // get the atom ID of the name string atom
  896.         myNameAtomID = EndianU32_BtoN(myHotSpotAtomData.nameAtomID);
  897.         
  898.         if (myNameAtomID != 0) {
  899.             QTAtomContainer        myNodeInfo;
  900.             QTAtom                myHSParentAtom;
  901.             QTAtom                myHSAtom;
  902.             QTAtom                myNameAtom = 0;
  903.             
  904.             // version 2.0 documentation says that the hot spot name is contained in a string atom
  905.             // that is a sibling of the hot spot atom (that is, a child of the hot spot parent atom);
  906.             // some other documents indicate that a string atom is always a sibling of the atom that
  907.             // contains the reference (in this case, a sibling of the hot spot information atom, and
  908.             // hence a child of the hot spot atom); we will look first in the hot spot atom and then
  909.             // in the hot spot parent atom. The version 2.1 documentation corrects the earlier error.
  910.             // Mea culpa!
  911.  
  912.             // get the hot spot parent atom and the hot spot atom
  913.             myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  914.             if (myErr == noErr) {
  915.                 myHSParentAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRHotSpotParentAtomType, 1, NULL);
  916.                 if (myHSParentAtom != 0) {
  917.                     myHSAtom = QTFindChildByID(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType, theHotSpotID, NULL);
  918.                     if (myHSAtom != 0) {
  919.                         QTAtom    myParentAtom;
  920.                         
  921.                         // look for a string atom that is a child of the hot spot atom
  922.                         myParentAtom = myHSAtom;
  923.                         myNameAtom = QTFindChildByID(myNodeInfo, myParentAtom, kQTVRStringAtomType, theHotSpotID, NULL);
  924.                         if (myNameAtom == 0) {
  925.                             // no such atom in the hot spot atom; look in the hot spot parent atom
  926.                             myParentAtom = myHSParentAtom;
  927.                             myNameAtom = QTFindChildByID(myNodeInfo, myParentAtom, kQTVRStringAtomType, theHotSpotID, NULL);
  928.                         }
  929.                         
  930.                         if (myNameAtom != 0)
  931.                             myHotSpotName = QTVRUtils_GetStringFromAtom(myNodeInfo, myParentAtom, myNameAtomID);
  932.                     }
  933.                 }
  934.             }
  935.             
  936.             QTDisposeAtomContainer(myNodeInfo);
  937.         }
  938.     }
  939.  
  940.     return(myHotSpotName);
  941. }
  942.  
  943.  
  944. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  945. //
  946. // Miscellaneous utilities.
  947. //
  948. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  949.  
  950.  
  951. //////////
  952. //
  953. // QTVRUtils_Point3DToPanAngle
  954. // Return the QTVR pan angle for a given QD3D point.
  955. // 
  956. //////////
  957.  
  958. float QTVRUtils_Point3DToPanAngle (float theX, float theY, float theZ)
  959. {
  960. #pragma unused(theY)
  961.  
  962.     float    myPan;
  963.     
  964.     if (theZ != 0.0) {
  965.         // note that atan always returns angles in the range -π/2 to π/2
  966.         myPan = atan(theX / theZ);
  967.         myPan = (theZ > 0) ? myPan + kVRPi : myPan;
  968.     } else {
  969.         myPan = (theX > 0) ? kVR3PiOver2 : kVRPiOver2;
  970.     }
  971.     
  972.     // make sure myPan is positive
  973.     while (myPan < 0.0)
  974.         myPan += kVR2Pi;
  975.  
  976.     return(myPan);
  977. }
  978.  
  979.  
  980. //////////
  981. //
  982. // QTVRUtils_Point3DToTiltAngle
  983. // Return the QTVR tilt angle for a given QD3D point.
  984. // 
  985. //////////
  986.  
  987. float QTVRUtils_Point3DToTiltAngle (float theX, float theY, float theZ)
  988. {
  989.     float            myTilt;
  990.     float            myDistance;
  991.     TQ3Point3D        myPoint;
  992.     
  993.     myPoint.x = theX;
  994.     myPoint.y = theY;
  995.     myPoint.z = theZ;
  996.     
  997.     myDistance = QTVRUtils_GetDistance(myPoint);
  998.     if (myDistance != 0.0)
  999.         myTilt = asin(theY / myDistance); 
  1000.     else
  1001.         myTilt = 0.0;
  1002.     
  1003.     return(myTilt);
  1004. }
  1005.  
  1006.  
  1007. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1008. //
  1009. // Node callback utilities.
  1010. //
  1011. // Use these to obtain standard behaviors when entering or exiting nodes.
  1012. //
  1013. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1014.  
  1015. //////////
  1016. //
  1017. // QTVRUtils_StandardEnteringNodeProc
  1018. // A standard procedure for entering a new node.
  1019. //
  1020. // This function performs actions that many applications will want done when entering a new node:
  1021. //    * display back button only if multinode movie
  1022. //    * display show-hot-spot button only if there are hotspots
  1023. //    * display the translate button only for object nodes that can translate
  1024. //    * (this space for rent)
  1025. //
  1026. //////////
  1027.  
  1028. PASCAL_RTN OSErr QTVRUtils_StandardEnteringNodeProc (QTVRInstance theInstance, long theNodeID, MovieController theMC)
  1029. {
  1030. #pragma unused(theNodeID)
  1031.  
  1032.     OSErr        myErr = noErr;
  1033.  
  1034.     if ((theInstance == NULL) || (theMC == NULL))
  1035.         return(paramErr);
  1036.         
  1037.     /////// 
  1038.     // all nodes
  1039.     /////// 
  1040.         
  1041.     // display the back button only if it's a multinode movie
  1042.     if (QTVRUtils_IsMultiNode(theInstance))
  1043.         QTUtils_ShowControllerButton(theMC, (long)mcFlagQTVRSuppressBackBtn);
  1044.     else
  1045.         QTUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressBackBtn);
  1046.  
  1047.     // display the show-hot-spot button only if there are hotspots in the node
  1048.     if (QTVRUtils_IsHotSpotInNode(theInstance))
  1049.         QTUtils_ShowControllerButton(theMC, (long)mcFlagQTVRSuppressHotSpotBtn);
  1050.     else
  1051.         QTUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressHotSpotBtn);
  1052.  
  1053.     /////// 
  1054.     // panoramic nodes
  1055.     /////// 
  1056.     
  1057.     if (QTVRUtils_IsPanoNode(theInstance)) {
  1058.     
  1059.         // hide the translate button
  1060.         QTUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressTranslateBtn);
  1061.         
  1062.     } else {
  1063.     
  1064.     /////// 
  1065.     // object nodes
  1066.     /////// 
  1067.         
  1068.         // show the translate button, but only if translation is available
  1069.         if (QTVRUtils_IsTranslateAvailable(theInstance))
  1070.             QTUtils_ShowControllerButton(theMC, (long)mcFlagQTVRSuppressTranslateBtn);
  1071.         else
  1072.             QTUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressTranslateBtn);
  1073.     }
  1074.     
  1075.     return(myErr);
  1076. }
  1077.  
  1078.  
  1079. //////////
  1080. //
  1081. // QTVRUtils_StandardLeavingNodeProc
  1082. // A standard procedure for leaving a node.
  1083. // This function performs actions that many applications will want done when leaving a node:
  1084. //    * (this space for rent)
  1085. //
  1086. // We assume that when this procedure is called, the application has decided NOT to cancel the move;
  1087. // accordingly, we always return false in theCancel.
  1088. //
  1089. //////////
  1090.  
  1091. PASCAL_RTN OSErr QTVRUtils_StandardLeavingNodeProc (QTVRInstance theInstance, long fromNodeID, long toNodeID, Boolean *theCancel, MovieController theMC)
  1092. {
  1093. #pragma unused(fromNodeID, toNodeID)
  1094.  
  1095.     OSErr        myErr = noErr;
  1096.  
  1097.     if ((theInstance == NULL) || (theMC == NULL))
  1098.         return(paramErr);
  1099.     
  1100.     // nothing yet....
  1101.  
  1102.     *theCancel = false;
  1103.     return(myErr);
  1104. }
  1105.  
  1106.